home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…tember: Reference Library / Dev.CD Sep 98 RL2.toast / What's New / Software Development Kits / MacOS USB DDK / Examples / PrinterClassDriver / TradDriverLoaderLib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-20  |  21.7 KB  |  768 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        TradDriverLoaderLib.c
  3.  
  4.     Contains:    Implementation for the pseudo-DriverLoaderLib for 'DRVR's.
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include <LowMem.h>
  13. #include <DriverGestalt.h>
  14. #include <TextUtils.h>
  15.  
  16. // Switched from using:
  17. //
  18. //   #include <PLStringFuncs.h>
  19. //
  20. // to using BlockMoveData because it's so hard to get PLstrcpy working
  21. // across a zillion different compilers.  *sigh*
  22.  
  23. #include "TradDriverLoaderLib.h"
  24.  
  25. ///////////////////////////////////////////////////////////////////////////
  26.  
  27. extern pascal SInt16 TradHigherDriverVersion(NumVersion *dv1, NumVersion *dv2)
  28. {
  29.     UInt16 nonRelRev1, nonRelRev2;
  30.  
  31.     if (dv1->majorRev           > dv2->majorRev)        return  1;
  32.     if (dv1->majorRev           < dv2->majorRev)        return -1;
  33.     if (dv1->minorAndBugRev     > dv2->minorAndBugRev)  return  1;
  34.     if (dv1->minorAndBugRev     < dv2->minorAndBugRev)  return -1;
  35.     if (dv1->stage              > dv2->stage)           return  1;
  36.     if (dv1->stage              < dv2->stage)           return -1;
  37.  
  38.     nonRelRev1 = dv1->nonRelRev;
  39.     nonRelRev2 = dv2->nonRelRev;
  40.     
  41.     if (dv1->stage == finalStage) {
  42.         if (dv1->nonRelRev == 0)                 nonRelRev1 = 0xFFFF;
  43.         if (dv2->nonRelRev == 0)                 nonRelRev2 = 0xFFFF;
  44.     }
  45.  
  46.     if (nonRelRev1 > nonRelRev2)                        return  1;
  47.     if (nonRelRev1 < nonRelRev2)                        return -1;
  48.  
  49.     return 0;
  50. }
  51.  
  52.  
  53. ///////////////////////////////////////////////////////////////////////////
  54.  
  55. extern pascal UnitNumber TradHighestUnitNumber(void)
  56.     // See comment in header file.
  57. {
  58.     return ( LMGetUnitTableEntryCount() - 1);
  59. }
  60.  
  61. ///////////////////////////////////////////////////////////////////////////
  62.  
  63. extern pascal Boolean TradDriverGestaltIsOn(DriverFlags flags)
  64.     // See comment in header file.
  65. {
  66.     return ( (flags & kmDriverGestaltEnableMask) != 0 );
  67. }
  68.  
  69. ///////////////////////////////////////////////////////////////////////////
  70.  
  71. static OSErr DriverGestaltOnOff(DriverRefNum refNum, Boolean setIt)
  72.     // This routine is called by TradDriverGestaltOn and
  73.     //  TradDriverGestaltOff to either set or clear the
  74.     //  kmDriverGestaltEnableMask bit in the DCE flags.
  75. {
  76.     OSErr err;
  77.     AuxDCEHandle thisDCE;
  78.     
  79.     // First called TradGetDriverInformation to validate the refNum
  80.     //  and verify that the driver exists.
  81.     err = TradGetDriverInformation(refNum, nil, nil, nil, nil);
  82.     if (err == noErr) {
  83.         thisDCE = (AuxDCEHandle) GetDCtlEntry(refNum);
  84.         if (setIt) {
  85.             (**thisDCE).dCtlFlags |= kmDriverGestaltEnableMask;
  86.         } else {
  87.             (**thisDCE).dCtlFlags &= ~kmDriverGestaltEnableMask;
  88.         }
  89.     }
  90.     
  91.     return (err);
  92. }
  93.  
  94. ///////////////////////////////////////////////////////////////////////////
  95.  
  96. extern pascal OSErr TradDriverGestaltOn(DriverRefNum refNum)
  97.     // See comment in header file.
  98. {
  99.     return ( DriverGestaltOnOff(refNum, true) );
  100. }
  101.  
  102. ///////////////////////////////////////////////////////////////////////////
  103.  
  104. extern pascal OSErr TradDriverGestaltOff(DriverRefNum refNum)
  105.     // See comment in header file.
  106. {
  107.     return ( DriverGestaltOnOff(refNum, false) );
  108. }
  109.  
  110. ///////////////////////////////////////////////////////////////////////////
  111.  
  112. extern pascal OSErr TradOpenInstalledDriver(DriverRefNum refNum, SInt8 ioPermission)
  113.     // See comment in header file.
  114. {
  115.     OSErr                 err;
  116.     Str255                driverName;
  117.     DriverRefNum    realRefNum;
  118.  
  119.     // Check parameters.
  120.     err = noErr;
  121.     if (ioPermission != fsRdWrPerm) {
  122.         err = paramErr;
  123.     }
  124.     
  125.     // Get the name of the driver, then simply open it.
  126.     if (err == noErr) {
  127.         err = TradGetDriverInformation(refNum, nil, nil, driverName, nil);
  128.     }
  129.     if (err == noErr) {
  130.         if ( driverName[0] == 0 ) {
  131.             err = paramErr;
  132.         }
  133.     }
  134.     if (err == noErr) {
  135.         err = OpenDriver(driverName, &realRefNum);
  136.     }
  137.     if (err == noErr) {
  138.         if (realRefNum != refNum) {
  139.             err = paramErr;        // My favourite error code -- at some intrinsic level, every error is a paramErr (-;
  140.         }
  141.     }
  142.     
  143.     return (err);
  144. }
  145.  
  146. ///////////////////////////////////////////////////////////////////////////
  147.  
  148. extern pascal OSErr TradLookupDrivers(UnitNumber beginningUnit,
  149.                                         UnitNumber endingUnit,
  150.                                         Boolean emptyUnits,
  151.                                         ItemCount *returnedRefNums, 
  152.                                         DriverRefNum *refNums)
  153.     // See comment in header file.
  154. {
  155.     OSErr err;
  156.     AuxDCEHandle     *unitTable;
  157.     ItemCount         maxRefNums;
  158.     UnitNumber         currentUnit;
  159.     
  160.     // Sanity check the parameters.
  161.     if ( endingUnit > TradHighestUnitNumber() ) {
  162.         endingUnit = TradHighestUnitNumber();
  163.     }
  164.     err = noErr;
  165.     if ( beginningUnit > TradHighestUnitNumber() ) {
  166.         err = badUnitErr;
  167.     }
  168.     if (err == noErr) {
  169.         if (beginningUnit > endingUnit ) {
  170.             err = paramErr;
  171.         }
  172.     }
  173.  
  174.     // Now do the real work...
  175.     if (err == noErr) {
  176.         unitTable = (AuxDCEHandle *) LMGetUTableBase();
  177.  
  178.         maxRefNums = *returnedRefNums;
  179.         
  180.         // Loop through each unit table entry from beginningUnit to endingUnit inclusive.
  181.         *returnedRefNums = 0;
  182.         currentUnit = beginningUnit;
  183.         while ( currentUnit <= endingUnit ) {
  184.  
  185.             // If we've still got space to return a unit...
  186.             if ( *returnedRefNums < maxRefNums ) {
  187.             
  188.                 // and we're interested in this unit...
  189.                 if (    (emptyUnits && unitTable[currentUnit] == nil) ||
  190.                             (!emptyUnits && unitTable[currentUnit] != nil) ) {
  191.                     
  192.                     // then copy the unit out to the caller's array
  193.                     refNums[*returnedRefNums] = ~currentUnit;
  194.                     *returnedRefNums += 1;
  195.                 }
  196.             }
  197.             currentUnit += 1;
  198.         }
  199.     
  200.     }
  201.     
  202.     return (err);
  203. }
  204.  
  205. ///////////////////////////////////////////////////////////////////////////
  206.  
  207. enum {
  208.     kNoUnitNumber = 0xFFFF
  209. };
  210.  
  211. static UnitNumber IsDriverInstalled(ConstStr255Param name, UnitNumber skipThisUnit)
  212.     // Look through the unit table to see if there is a driver with this name
  213.     //  already installed.  Note that you might consider calling OpenDriver
  214.     //  here, but that would be wrong.  OpenDriver has similar semantics, but
  215.     //  if it fails to find a driver in the unit table it will search the
  216.     //  current resource chain looking for a DRVR resource to install.
  217.     //  Given that it's likely our client has a DRVR resource in their
  218.     //  resource chain ('cause they're messing around trying to install
  219.     //  drivers), and that OpenDriver will install it without detaching
  220.     //  it from the client's resource file, and that the client's
  221.     //  resource file may go away (ie they're a DropMounter-like application
  222.     //  or some INIT running at system startup), this would be bad.
  223. {
  224.     UnitNumber    endingUnit;
  225.     UnitNumber    unit;
  226.     Str255            unitName;
  227.     
  228.     endingUnit = TradHighestUnitNumber();
  229.     
  230.     for (unit = 0; unit <= endingUnit; unit++) {
  231.         if ( TradGetDriverInformation(~unit, nil, nil, unitName, nil) == noErr) {
  232.             if ( unit != skipThisUnit && EqualString(name, unitName, false, true) ) {
  233.                 return (unit);
  234.             }
  235.         }
  236.     }
  237.     
  238.     return (kNoUnitNumber);
  239. }
  240.  
  241. ///////////////////////////////////////////////////////////////////////////
  242.  
  243. enum {
  244.     kMaximumNumberOfUnitTableEntries = 1024,
  245.     // kMaximumNumberOfUnitTableEntries = 8000,
  246.     
  247.     // kMaximumNumberOfUnitTableEntries is documented in Technote
  248.     //  DV 23 "Driver Education" <http://devworld.apple.com/dev/technotes/dv/dv_23.html>
  249.     //  as being the maximum size that the classic Device Manager
  250.     //  would grow the unit table.  In theory, this limits the system
  251.     //  to 128 unit table entries.
  252.     // However the traditional Mac OS is capable of dealing with much more
  253.     //  than 128 units.  In fact, some multi-port serial card vendors
  254.     //  regularly install more.
  255.     // Prior to Mac OS 8, the PCI DriverLoaderLib enforced the 128 limit.
  256.     //  I filed a bug against the PCI DriverLoaderLib to get this limit
  257.     //  raised, and the new limit under Mac OS 8 is 1024.
  258.     // Given that official sanction, I have now raised the standard
  259.     //  limit enforced by this library to 1024.  I supply an alternative
  260.     //  maximum (8000), designed to keep the unit table smaller than 32K.
  261.     //  This is important because many people use 68K word indexing
  262.     //  (ie x(a0,d0.w) to to access the entries.
  263.     // I have tested TradDriverLoaderLib installing up to 500 device
  264.     //  drivers.  
  265.     
  266.     kNumberOfEntriesToGrowUnitTable = 4
  267.     
  268.     // Technote DV 23 "Driver Education"
  269.     //  <http://devworld.apple.com/dev/technotes/dv/dv_23.html>
  270.     //  documents that the system grows the unit table by 4 entries
  271.     //  at a time.
  272. };
  273.  
  274. ///////////////////////////////////////////////////////////////////////////
  275.  
  276. static OSErr GrowUnitTable()
  277.     // This routine grows the unit table by kNumberOfEntriesToGrowUnitTable,
  278.     //  up to a maximum of kMaximumNumberOfUnitTableEntries.  The routine
  279.     //  is guaranteed to grow the table by at least one entry, or fail
  280.     //  with an error.
  281. {
  282.     OSErr        err;
  283.     Ptr         oldTable;
  284.     Ptr         newTable;
  285.     UInt32    oldCount;
  286.     UInt32    newCount;
  287.  
  288.     // Get the info about the old table, and calculate the new table size.    
  289.     oldTable = LMGetUTableBase();
  290.     oldCount = LMGetUnitTableEntryCount();
  291.     newCount = oldCount + kNumberOfEntriesToGrowUnitTable;
  292.  
  293.     // Guard against growing the table too big.    
  294.     err = noErr;
  295.     if (newCount > kMaximumNumberOfUnitTableEntries) {
  296.         err = unitTblFullErr;
  297.     }
  298.     
  299.     // Allocate the new unit table in the system heap.  Note that we
  300.     //  clear the newly allocated memory, so that later on, when we
  301.     //  use this memory as the new unit table, the newly allocated
  302.     //  entries will be empty.
  303.  
  304.     if (err == noErr) {
  305.         newTable = NewPtrSysClear( newCount * sizeof(AuxDCEHandle));
  306.         err = MemError();
  307.     }
  308.  
  309.     // Copy the unit table entries over to the new table and then switch
  310.     //  to that table.  Note that this sequence doesn't disable interrupts,
  311.     //  instead it relies on the fact that programs can't modify the
  312.     //  unit table at interrupt time, and thus we, running at non-interrupt
  313.     //  time, have exclusive write access to the table.
  314.  
  315.     // Note that the sequence of these next few lines is *very* important.
  316.     //  If we did this in any other order, you could get to a situation
  317.     //  where interrupt code might be looking at an inconsistent 
  318.     //  unit table, which would be bad.
  319.     
  320.     // The sequence is:
  321.     //  1. copy the old unit table entries to the new table
  322.     //  2. change the unit table base pointer, so that interrupts
  323.     //         start using the new unit table
  324.     //  3. then change the unit table count, so that we have
  325.     //         more entries available
  326.     
  327.     if (err == noErr) {
  328.         BlockMoveData(oldTable, newTable, oldCount * sizeof(AuxDCEHandle));    // 1.
  329.         LMSetUTableBase(newTable);                                                                                    // 2.
  330.         LMSetUnitTableEntryCount(newCount);                                                                    // 3.
  331.         
  332.         // Now its safe to dispose of the old unit table.
  333.         DisposePtr(oldTable);
  334.     }
  335.  
  336.     return (err);    
  337. }
  338.  
  339. ///////////////////////////////////////////////////////////////////////////
  340.  
  341. static OSErr FindFreeUnitNumber(UnitNumber beginningUnit,
  342.                                 UnitNumber endingUnit, 
  343.                                 UnitNumber *foundUnit)
  344.     // This routine walks the unit table looking for a free
  345.     //  slot.  The slot must be between beginningUnit
  346.     //  and endingUnit.  If endingUnit is greater than
  347.     //  TradHighestUnitNumber(), then we're allowed
  348.     //  to grow the unit table to meet our needs.
  349. {
  350.     OSErr err;
  351.     Boolean found;
  352.     UnitNumber currentUnit;
  353.     UnitNumber trueEndingUnit;
  354.     AuxDCEHandle *unitTable;
  355.     
  356.     unitTable = (AuxDCEHandle *) LMGetUTableBase();
  357.     
  358.     // Find trueEndingUnit, which is the minimum
  359.     //  of endingUnit and the highest unit number.
  360.     trueEndingUnit = endingUnit;
  361.     if ( trueEndingUnit > TradHighestUnitNumber() ) {
  362.         trueEndingUnit = TradHighestUnitNumber();
  363.     }
  364.  
  365.     // Scan through the unit table, starting at beginningUnit
  366.     //  and ending at trueEndingUnit, looking for an
  367.     //  empty slot.
  368.     currentUnit = beginningUnit;
  369.     found = false;
  370.     while (currentUnit <= trueEndingUnit && !found) {
  371.         found = (unitTable[currentUnit] == nil);
  372.         if (!found) {
  373.             currentUnit += 1;
  374.         }
  375.     }
  376.  
  377.     // Finish up.    
  378.     if (found) {
  379.         // We found an empty slot, return it.
  380.         *foundUnit = currentUnit;
  381.         err = noErr;
  382.     } else {
  383.  
  384.         // We didn't find an empty slot.  If we're
  385.         //  allowed to, grow the unit table, otherwise
  386.         //  just return an error.
  387.         
  388.         if (endingUnit > trueEndingUnit) {
  389.             err = GrowUnitTable();
  390.             if (err == noErr) {
  391.                 *foundUnit = trueEndingUnit + 1;
  392.             }
  393.         } else {
  394.             err = unitTblFullErr;
  395.         }
  396.     }
  397.     
  398.     return (err);    
  399. }
  400.  
  401. ///////////////////////////////////////////////////////////////////////////
  402.  
  403. extern pascal OSErr TradInstallDriverFromPtr(DRVRHeaderPtr driver,
  404.                                                 UnitNumber beginningUnit,
  405.                                                 UnitNumber endingUnit,
  406.                                                 DriverRefNum *refNum)
  407.     // See comment in header file.
  408. {
  409.     OSErr err;
  410.     UnitNumber foundUnit;
  411.     AuxDCEHandle theDCE;
  412.     
  413.     // Sanity check parameters.
  414.     err = noErr;
  415.     if ( driver == nil ) {
  416.         err = paramErr;
  417.     }
  418.     if ( beginningUnit > TradHighestUnitNumber() ) {
  419.         err = badUnitErr;
  420.     }
  421.     if ( err == noErr && beginningUnit > endingUnit ) {
  422.         err = paramErr;
  423.     }
  424.     
  425.     // Check whether this driver is already installed.
  426.     if ( err == noErr ) {
  427.         // Check whether it's already installed.
  428.         foundUnit = IsDriverInstalled(&driver->drvrName[0], kNoUnitNumber);
  429.         if (foundUnit != kNoUnitNumber) {
  430.             // Return the refnum of the existing driver to the caller.
  431.             *refNum = ~foundUnit;
  432.             err = dupFNErr;
  433.         }
  434.     }
  435.     
  436.     // Now walk the unit table looking for a free slot.
  437.     if (err == noErr) {
  438.         err = FindFreeUnitNumber(beginningUnit, endingUnit, &foundUnit);
  439.     }
  440.  
  441.     // We've got a free slot, so let's install the device driver.
  442.     //  Note that we use DriverInstallReserveMem, rather than the standard
  443.     //  DriverInstall, so that the DCE is allocated low in the system
  444.     //  heap.  DriverInstallReserveMem was introduced with the 128K ROM.
  445.  
  446.     if (err == noErr) {
  447.         err = DriverInstallReserveMem(driver, ~foundUnit);
  448.     }
  449.     
  450.     // Now do some important tidying up.
  451.     if (err == noErr) {
  452.  
  453.         // Return the refNum to the caller.
  454.         *refNum = ~foundUnit;
  455.  
  456.         theDCE = (AuxDCEHandle) GetDCtlEntry(*refNum);
  457.         
  458.         // Now setup the DCE properly.  There's a whole pile of things we
  459.         //  have to do, mainly because DriverInstall is such a brain-dead
  460.         //  routine.
  461.         
  462.         // First up, DriverInstall seems to ignore the first parameter
  463.         //  passed to it, so we have to blat the pointer to the driver code in
  464.         //  yourself afterwards.
  465.         
  466.         (**theDCE).dCtlDriver = (Ptr) driver;
  467.  
  468.         // Then we have to set up the flags.  We do this by copying the flags
  469.         //  out of the first word of the driver code.  We make sure to clear
  470.         //  the dRAMBased bit because we're actually a pointer-based driver
  471.         //  and DriverInstallReserveMem sets it to provisionally indicate that
  472.         //  we're a handle based driver.  We also set dNeedLock because
  473.         //  we want the the Device Manager to lock down the DCE.
  474.         
  475.         (**theDCE).dCtlFlags = (driver->drvrFlags & ~dRAMBasedMask) | dNeedLockMask;
  476.  
  477.         // There's also a bunch of fields we copy straight across without
  478.         //  any modification.  You might expect DriverInstall to copy
  479.         //  across these fields from the driver header to the DCE, but it doesn't
  480.         //  do that, so we do it ourselves.
  481.  
  482.         (**theDCE).dCtlDelay = driver->drvrDelay;
  483.         (**theDCE).dCtlEMask = driver->drvrEMask;
  484.         (**theDCE).dCtlMenu  = driver->drvrMenu;
  485.  
  486.         // Finally, we lock the DCE.
  487.         // Note that strictly speaking we don't need to HLock the DCE
  488.         //  because the Device Manager will do it when it you open a driver
  489.         //  that has dNeedLock set.  However, we want to
  490.         //  lock it now because DriverInstallReserveMem has just made sure
  491.         //  that the DCE was created low in the system heap, so we might as
  492.         //  well lock it down low rather than let it float.
  493.  
  494.         HLock( (Handle) theDCE );
  495.     }
  496.     
  497.     return (err);
  498. }
  499.  
  500. ///////////////////////////////////////////////////////////////////////////
  501.  
  502. extern pascal OSErr TradInstallDriverFromHandle(DRVRHeaderHandle driver,
  503.                                                 UnitNumber beginningUnit,
  504.                                                 UnitNumber endingUnit,
  505.                                                 DriverRefNum *refNum)
  506.     // See comment in header file.
  507. {
  508.     OSErr err;
  509.     Size  driverSize;
  510.     DRVRHeaderPtr driverPtr;
  511.     
  512.     driverPtr = nil;
  513.     
  514.     err = noErr;
  515.     if (driver == nil || *driver == nil) {
  516.         err = paramErr;
  517.     }
  518.     if (err == noErr) {
  519.         driverSize = GetHandleSize( (Handle) driver );
  520.     }
  521.     if (err == noErr) {
  522.         driverPtr = (DRVRHeaderPtr) NewPtrSys( driverSize );
  523.         err = MemError();
  524.     }
  525.     
  526.     if (err == noErr) {
  527.         // This is *not* a BlockMoveData call. This time, we really are moving code!
  528.         //  I could have put cache flushing code in here, but then I would have
  529.         //  had to check whether it was available or not.
  530.         BlockMove( *driver, driverPtr, driverSize );
  531.         
  532.         err = TradInstallDriverFromPtr(driverPtr, beginningUnit, endingUnit, refNum);
  533.     }
  534.     
  535.     // Clean up.
  536.     if (err != noErr) {
  537.         // We're returning an error.  The API says we should leave the handle untouched,
  538.         //  but we should definitely clean up our new copy of the driver code.
  539.         if (driverPtr != nil) {
  540.             DisposePtr( (Ptr) driverPtr );
  541.         }
  542.     }
  543.     
  544.     return (err);
  545. }
  546.  
  547. ///////////////////////////////////////////////////////////////////////////
  548.  
  549. extern pascal OSErr TradInstallDriverFromResource(SInt16 rsrcID, StringPtr rsrcName,
  550.                                                 UnitNumber beginningUnit,
  551.                                                 UnitNumber endingUnit,
  552.                                                 DriverRefNum *refNum)
  553.     // See comment in header file.
  554. {
  555.     OSStatus err;
  556.     Handle driverHandle;
  557.     
  558.     // Note: We don't care which zone the resource gets loaded, because 
  559.     //  TradInstallDriverFromHandle makes a copy of it anyway.
  560.  
  561.     // Get the resource, using either rsrcID or rsrcName.
  562.     if (rsrcName == nil) {
  563.         driverHandle = Get1Resource('DRVR', rsrcID);
  564.     } else {
  565.         driverHandle = Get1NamedResource('DRVR', rsrcName);
  566.     }
  567.     
  568.     // Set err if we couldn't get the resource.
  569.     if (driverHandle == nil) {
  570.         err = ResError();
  571.         if (err == noErr) {
  572.             err = resNotFound;
  573.         }
  574.     } else {
  575.         // Make sure we're not killed by some clown making the 'DRVR' purgeable.
  576.         HNoPurge(driverHandle);                    
  577.         err = MemError();
  578.     }
  579.     
  580.     // Now install the driver as if we'd got it from a memory handle.    
  581.     if (err == noErr) {
  582.         err = TradInstallDriverFromHandle( (DRVRHeaderHandle) driverHandle, beginningUnit, endingUnit, refNum);
  583.  
  584.         ReleaseResource(driverHandle);
  585.         if (err == noErr) {
  586.             err = ResError();
  587.         }
  588.     }
  589.     
  590.     return (err);
  591. }
  592.  
  593. ///////////////////////////////////////////////////////////////////////////
  594.  
  595. extern pascal OSErr TradGetDriverInformation(DriverRefNum refNum,
  596.                                                 UnitNumber *thisUnit,
  597.                                                 DriverFlags *flags,
  598.                                                 StringPtr name,
  599.                                                 DRVRHeaderPtr *driverHeader
  600.                                                 )
  601.     // See comment in header file.
  602. {
  603.     OSErr err;
  604.     UnitNumber             tmpUnit;
  605.     AuxDCEHandle        tmpDCE;
  606.     DRVRHeaderPtr        tmpHeader;
  607.     DRVRHeaderHandle    tmpDriverHandle;
  608.     
  609.     // Get some initial information.
  610.     tmpUnit = ~refNum;
  611.     
  612.     // Sanity check the refNum parameter.
  613.     err = noErr;
  614.     if (tmpUnit > TradHighestUnitNumber()) {
  615.         err = badUnitErr;
  616.     }
  617.     if (err == noErr) {
  618.         tmpDCE = (AuxDCEHandle) GetDCtlEntry(refNum);
  619.         if ( tmpDCE == nil ) {
  620.             err = unitEmptyErr;
  621.         }
  622.     }
  623.     if (err == noErr) {
  624.         if ( (*tmpDCE == nil) || (GetHandleSize( (Handle) tmpDCE) < sizeof(DCtlEntry)) ) {
  625.             err = dceExtErr;
  626.         }
  627.     }
  628.     
  629.     // Get the information from the DCE.
  630.     if (err == noErr) {
  631.  
  632.         // From the DCE, find the DRVR header.  This can fail for a number of reasons:
  633.         //     1. dCtlDriver is nil
  634.         //     2. the driver is handle based, and the handle's master point is nil
  635.         //     3. the driver is handle based, and the driver's handle is too small
  636.         // In all of these cases, we set tmpHeader to nil, returning nil to our
  637.         // client.
  638.         
  639.         tmpHeader = (DRVRHeaderPtr) (**tmpDCE).dCtlDriver;
  640.         if ( tmpHeader != nil ) {
  641.             if ( ((**tmpDCE).dCtlFlags & dRAMBasedMask) != 0 ) {
  642.  
  643.                 tmpDriverHandle = (DRVRHeaderHandle) tmpHeader;
  644.                 
  645.                 if ( (*tmpDriverHandle != nil) &&
  646.                             (GetHandleSize( (Handle) tmpDriverHandle) >= sizeof(DRVRHeader)) ) {
  647.                     tmpHeader = *tmpDriverHandle;
  648.                 }
  649.             }
  650.         }
  651.         
  652.         // Now copy out the various requested parameters
  653.         if (thisUnit != nil) {
  654.             *thisUnit = tmpUnit;
  655.         }
  656.         if (flags != nil) {
  657.             *flags = (**tmpDCE).dCtlFlags;
  658.         }
  659.         if (name != nil) {
  660.             if ( tmpHeader == nil ) {
  661.                 name[0] = 0;
  662.             } else {
  663.                 BlockMoveData(&tmpHeader->drvrName[0], name, tmpHeader->drvrName[0] + 1);
  664.             }
  665.         }
  666.         if (driverHeader != nil) {
  667.             *driverHeader = tmpHeader;
  668.         }
  669.     }
  670.     
  671.     return (err);
  672. }
  673.  
  674. ///////////////////////////////////////////////////////////////////////////
  675.  
  676. extern pascal OSErr TradRemoveDriver(DriverRefNum refNum, Boolean immediate)
  677.     // See comment in header file.
  678. {
  679.     OSErr                 err;
  680.     DriverFlags     flags;
  681.     DRVRHeaderPtr driverHeader;
  682.  
  683.     // Check parameters.
  684.     err = noErr;
  685.     if (immediate) {
  686.         err = paramErr;
  687.     }
  688.  
  689.     // Get information about the driver we're closing.
  690.     if (err == noErr) {
  691.         err = TradGetDriverInformation(refNum, nil, &flags, nil, &driverHeader);
  692.     }
  693.     if (err == noErr) {
  694.         if ( driverHeader == nil ) {
  695.             err = paramErr;
  696.         }
  697.     }
  698.     
  699.     // If the driver is open, close it.
  700.     if (err == noErr) {
  701.         if ( (flags & dOpenedMask) != 0 ) {
  702.             err = CloseDriver(refNum);
  703.         }
  704.     }
  705.     
  706.     // Now call the system to remove the driver from the unit table.  Note that this
  707.     //  works because of a subtlety in DriverRemove.  If the driver being removed
  708.     //  is a RAM-based driver (which our drivers aren't), DriverRemove will call
  709.     //  ReleaseResource on the dCtlDriver.  We don't want this, so we make our drivers
  710.     //  not RAM-based.
  711.     
  712.     if (err == noErr) {
  713.         err = DriverRemove(refNum);
  714.     }
  715.     
  716.     if (err == noErr) {
  717.         // All is cool, so let's dispose of the code.
  718.         DisposePtr( (Ptr) driverHeader);
  719.     }
  720.     
  721.     return (err);
  722. }
  723.  
  724. ///////////////////////////////////////////////////////////////////////////
  725.  
  726. extern pascal OSErr TradRenameDriver(DriverRefNum refNum, ConstStr255Param newDriverName)
  727.     // See *important* comment in header file.
  728. {
  729.     OSErr             err;
  730.     Str255             driverName;
  731.     DRVRHeaderPtr     driverHeader;
  732.     
  733.     err = noErr;
  734.     if ( newDriverName[0] == 0 ) {
  735.         err = paramErr;
  736.     }
  737.     if (err == noErr) {
  738.         // Get information about the driver we're renaming.
  739.         err = TradGetDriverInformation(refNum, nil, nil, driverName, &driverHeader);
  740.     }
  741.     if (err == noErr) {
  742.         if ( driverHeader == nil ) {
  743.             err = paramErr;
  744.         }
  745.     }
  746.     
  747.     // Now check the name lengths.  See comment in implementation for details.
  748.     if (err == noErr) {
  749.         if ( newDriverName[0] > driverName[0] ) {
  750.             err = paramErr;
  751.         }
  752.     }
  753.     
  754.     // Now check whether the new name is already present in the unit table.
  755.     if (err == noErr) {
  756.         if ( IsDriverInstalled(newDriverName, ~refNum) != kNoUnitNumber ) {
  757.             err = dupFNErr;
  758.         }
  759.     }
  760.     
  761.     // Now copy in the new driver name.
  762.     if (err == noErr) {
  763.         BlockMoveData( newDriverName, &driverHeader->drvrName[0], newDriverName[0] + 1 );
  764.     }
  765.     
  766.     return (err);
  767. }
  768.